home *** CD-ROM | disk | FTP | other *** search
- ; REPEATS.ASM
- ; Format: REPEATS [d:][/P]
- ; Returns with duplicate file names.
-
- CODE SEGMENT ;*************************
- ASSUME CS:CODE,DS:CODE ;* *
- ORG 100H ;* REMEMBER TO EXE2BIN *
- ;* *
- START: JMP BEGINNING ;*************************
-
- ; DATA AREA
- ; ---------
- COPYRIGHT DB 'Copyright 1987 Ziff-Davis Publishing Co.',1AH
- PROGRAMMER DB 'Michael J. Mefford'
- GLOBAL DB '*.*',0
- PARENT DB '..',0
- ROOT DB '\',0
-
- DIR_OFFSET DW 0
- CURRENT_DRIVE DB ?
- DIR_COUNT DW 0
- FILE_COUNT DW 0
- FILE_START DW ?
- END_OF_SPACE DW ?
-
- PRINT_FLAG DB 0
- MATCH_FLAG DB 0
- DISPLAY_FLAG DB 0
- SOURCE_FLAG DB 0
-
- SEARCHING DB 13,10,'Searching ',0
- FOR DB ' for duplicate file names.',13,10
- DB 'Loading directories...patience please',13,10,0
- LOADING_FILE DB 'Loading file names...',0
- DIRECTORY DB 13,10,' Directory ',0
- NO_MATCHES DB 7,13,10,'No duplicates found.',13,10,0
- DONE DB 7,13,10,13,10,'Search sucessfully completed.',13,10,0
- NOT_ENOUGH DB 'Not enough memory',0
-
- DIR_ATTRIBUTE EQU 10H
- ALL_FILES EQU 6H
-
- ;-------------------------------------------------------------;
- ; First allocate 64K and move the stack to the end of code. ;
- ; Then get the current drive so we can restore upon exit. ;
- ; Next check for a drive request and/or printer echo switch. ;
- ; Save current directory. Display search request. And finally ;
- ; initialize the directory level subscripts to one. ;
- ;-------------------------------------------------------------;
-
- BEGINNING: CLD ;All string instructions forward.
- MOV BX,1000H ;64K (1000h paragraphs).
- MOV AH,4AH ;Modify allocated memory.
- INT 21H
- MOV SI,OFFSET NOT_ENOUGH ;Exit if 64K not available.
- JNC GOT_64K
- JMP PRINT_DONE
-
- GOT_64K: MOV SP,OFFSET STACK_SPACE+1FFH ;Move stack to end of code.
- MOV AH,19H ;Get the current drive
- INT 21H
- MOV CURRENT_DRIVE,AL ; and save.
-
- MOV CL,DS:[80H] ;Get the length of the argument.
- CMP CL,0 ;If it's zero then no parameters.
- JZ NO_PARA
- XOR CH,CH ;Else, zero in high half.
- MOV SI,81H ;Point to parameter.
- NEXT_PARA: CMP BYTE PTR [SI],':' ;Is it colon?
- JNZ CK_SWITCH ;If no, check switch.
- MOV DL,[SI-1] ;Else, get drive request.
- AND DL,5FH ;Capitalize.
- SUB DL,'A' ;Convert to DOS format.
- MOV AH,0EH ;And change drive.
- INT 21H
- CK_SWITCH: CMP BYTE PTR [SI],'/' ;Is it switch request?
- JNZ LOOP_PARA ;If no, next parameter.
- MOV DL,[SI+1] ;Else, get request.
- AND DL,5FH ;Capitalize.
- CMP DL,'P' ;Is it printer request?
- JNZ LOOP_PARA ;If no, next parameter.
- MOV PRINT_FLAG,1 ;Else, flag printer echo.
- LOOP_PARA: INC SI ;Point to next byte
- LOOP NEXT_PARA ; and get next byte.
-
- NO_PARA: MOV BYTE PTR CURRENT_DIR,'\'
- MOV SI,OFFSET CURRENT_DIR+1 ;Save the current directory.
- CALL GET_DIR
-
- MOV SI,OFFSET SEARCHING ;Print "Searching ".
- CALL WRITE_STRING
- MOV AH,19H ;Get current drive.
- INT 21H
- MOV DL,AL
- ADD DL,'A' ;Convert to ASCII
- CALL DISPLAY ; and display.
- MOV DL,':' ;Display the colon.
- CALL DISPLAY
- MOV SI,OFFSET FOR ;Display balance of intro.
- CALL WRITE_STRING
-
- CLD ;All string instructions will be
- MOV AL,1 ; done in a forward direction.
- MOV CX,100 ;Initialize directory subscripts
- MOV DI,OFFSET SUBSCRIPTS ;to one.
- REP STOSB
-
- MOV DX,OFFSET DTA ;Point the disk transfer address
- CALL CHANGE_DTA ; to the end of code.
-
- ;------------------------------------------------------------;
- ; This routine will systematically change directories up and ;
- ; down the directory tree, and store the directory names. ;
- ;------------------------------------------------------------;
-
- MOV SI,OFFSET DIRECTORIES+1 ;Point to storage.
- MOV BP,OFFSET SUBSCRIPTS ;Point to subscripts.
- MOV DX,OFFSET ROOT ;Point to root.
-
- STORE_DIR: MOV AH,0BH ;Check for Ctrl Break.
- INT 21H
- CALL CHANGE_DIR
- INC DIR_COUNT
- MOV BYTE PTR [SI-1],'\' ;DOS fails to preface with "\"
- CALL GET_DIR ; so we have to.
- ADD SI,65 ;Point to next storage.
- ADD DIR_OFFSET,65 ;Update the offset as well.
- JMP SHORT FIRST_DIR
-
- PARENT_DIR: CMP BP,OFFSET SUBSCRIPTS ;When we try to return to parent
- JZ FILENAMES ; directory and are in root, we
- MOV DX,OFFSET PARENT ; are done. Otherwise, change
- CALL CHANGE_DIR ; to parent directory.
- MOV BYTE PTR DS:[BP],1 ;Put one back in previous level
- DEC BP ; and point to parent level.
-
- FIRST_DIR: XOR BL,BL ;BL as pointer to directory no.
- MOV DX,OFFSET GLOBAL
- MOV CX,DIR_ATTRIBUTE ;Ask for global match.
- CALL FIND_FIRST ;Find first matching.
- JC PARENT_DIR
- CK_DIR: CMP BYTE PTR DTA+21,10H ;If not a directory get next.
- JNZ NEXT_DIR
- CMP BYTE PTR DTA+30,'.' ;If a dot directory get next.
- JZ NEXT_DIR
- INC BL ;Increment position in directory.
- CMP BL,DS:[BP] ;Continue until new directory.
- JNZ NEXT_DIR
- INC BYTE PTR DS:[BP] ;Update variables.
- MOV DX,OFFSET DTA+30
- CALL CHANGE_DIR
- INC BP
- JMP SHORT STORE_DIR
-
- NEXT_DIR: CALL FIND_NEXT ;Get all subdirectories in current
- JC PARENT_DIR ; directory then go to parent.
- JMP SHORT CK_DIR
-
- ;-----------------------------------------------;
- ; This routine finds and stores all file names. ;
- ;-----------------------------------------------;
-
- FILENAMES: CMP DIR_COUNT,1 ;If only one directory
- JNZ ALLOCATE ; then can't be any duplicates.
- JMP EXIT
- ALLOCATE: ADD SI,15 ;Else, adjust for truncation.
- MOV CL,4 ;Convert end of current storage
- SHR SI,CL ; into segment address.
- MOV BX,SI
- MOV AH,4AH ;Deallocate memory.
- INT 21H
-
- MOV BX,0FFFFH ;See how much memory is left.
- MOV AH,48H
- INT 21H
- MOV AH,4AH ;Ask for it all.
- INT 21H
-
- MOV CX,ES ;Get extra segment.
- ADD CX,SI ;Change to end of storage.
- MOV ES,CX
- MOV FILE_START,CX ;Store as start of file storage.
- ADD BX,CX ;Add allocated memory.
- MOV END_OF_SPACE,BX ;Store end of workspace.
-
- MOV SI,OFFSET LOADING_FILE ;Tell user, loading file names.
- CALL WRITE_STRING
- MOV DIR_OFFSET,OFFSET DIRECTORIES ;Store directory start.
- XOR BP,BP ;BP as directory counter.
- FIRST_FILE: MOV AH,0BH ;Check for control break.
- INT 21H
- INC BP ;Increment directory count.
- CMP BP,DIR_COUNT ;Done all directories?
- JA DUPLICATES ;If yes, search for duplicates.
- MOV DX,DIR_OFFSET ;Else, change directory.
- CALL CHANGE_DIR
- ADD DIR_OFFSET,65 ;Point to next directory.
- MOV DX,OFFSET GLOBAL
- MOV CX,ALL_FILES
- CALL FIND_FIRST ;Find first matching file.
- JNC STORE_FILE ;If empty, next directory.
- JMP SHORT FIRST_FILE ;Else, store data.
-
- NEXT_FILE: MOV AX,ES ;Retrieve data segment.
- ADD AX,2 ;Point to next storage.
- MOV ES,AX
- MOV SI,OFFSET NOT_ENOUGH ;Assume out of memory.
- CMP AX,END_OF_SPACE ;Is it true?
- JB CONTINUE ;If no, continue.
- JMP EXIT ;Else, exit.
-
- CONTINUE: CALL FIND_NEXT ;Find next matching.
- JC FIRST_FILE ;If done, next directory.
- STORE_FILE: INC FILE_COUNT ;Else, increment file count.
- MOV SI,OFFSET DTA+22 ;Store filename data.
- XOR DI,DI ;Point to first byte.
- MOV AX,BP
- STOSW ;Store directory number.
- MOV CX,4 ;Store file date and size data.
- REP MOVSW
-
- MOV CX,12 ;Store 12 bytes of filename.
- NEXT_STORE: LODSB ;Get a byte.
- CMP AL,0 ;End of filename?
- JZ END_STORE ;If yes, finish with blanks.
- CMP AL,'.' ;Is it the period?
- JNZ STORE_BYTE ;If no, store.
- SUB CX,3 ;Else store 3 spaces.
- MOV AL,32
- REP STOSB
- ADD CX,3
- JMP SHORT NEXT_STORE ;Get next byte.
-
- STORE_BYTE: STOSB ;Store byte.
- LOOP NEXT_STORE ;Get next byte.
- END_STORE: MOV AL,32 ;Pad balance with spaces.
- REP STOSB
- MOV AL,0 ;Tack on a zero for display
- STOSB ; control.
- JMP SHORT NEXT_FILE ;Get next filename.
-
- ;-------------------------------------------------------------;
- ; This routine does the work of finding duplicate file names. ;
- ;-------------------------------------------------------------;
-
- DUPLICATES: MOV WORD PTR ES:[0],0FFFFH ;Tack on -1 signature.
- MOV SI,OFFSET SEARCHING ;Tell user searching now.
- CALL WRITE_STRING
- MOV AX,FILE_START ;Retrieve start of file names.
- JMP SHORT STORE_SOURCE
-
- NEXT_SOURCE: MOV AH,0BH ;Check for Ctrl Break.
- INT 21H
- MOV CS:SOURCE_FLAG,0 ;Reset source display flag.
- MOV AX,ES
- ADD AX,2 ;Increment to next file name.
- STORE_SOURCE: MOV DS,AX
- MOV ES,AX
- CMP WORD PTR DS:[32],0FFFFH ;End of file name storage?
- JZ EXIT ;If yes, we are done.
- MOV BP,ES:[0] ;Retrieve directory number.
- CMP BP,0 ;Have we matched this one before?
- JZ NEXT_SOURCE ;If yes, get next.
-
- NEXT_MATCH: MOV AX,DS
- ADD AX,2 ;Point to next target file name.
- MOV DS,AX
- MOV SI,0
- LODSW ;Retrieve directory number.
- CMP AX,0FFFFH ;End of file storage?
- JZ NEXT_SOURCE ;If yes, get next file name.
- CMP AX,BP ;In same directory?
- JZ NEXT_MATCH ;If yes, get next file name.
-
- MOV SI,10 ;Else, point to source and
- MOV DI,10 ; and target file names.
- MOV CX,6
- REPZ CMPSW ;Are they duplicates?
- JNZ NEXT_MATCH ;If no, next file name.
- CALL PRINT_MATCH ;Else, print match.
- MOV WORD PTR DS:[0],0 ;Flag as matched.
- JMP SHORT NEXT_MATCH ;Get next file name.
-
- ;------------------------------------------------;
- ; Exit routine. Restore default drive and ;
- ; directories. Display appropriate exit message. ;
- ;------------------------------------------------;
-
- EXIT: PUSH CS ;Restore data segment.
- POP DS
- MOV DX,OFFSET CURRENT_DIR ;Restore default drive
- CALL CHANGE_DIR ; directory
- MOV DL,CURRENT_DRIVE ; and drive.
- MOV AH,0EH
- INT 21H
- MOV SI,OFFSET DONE
- CMP MATCH_FLAG,1 ;If match was found, display
- JZ PRINT_DONE ;"successful"
- MOV SI,OFFSET NO_MATCHES ;else, display "none found".
- PRINT_DONE: PUSH CS
- POP DS
- CALL WRITE_STRING
- INT 20H ;Terminate.
-
- ;*************;
- ; SUBROUTINES ;
- ;*************;
-
- ;-------------------------------------------;
- ; These subroutines are DOS function calls. ;
- ;-------------------------------------------;
-
- GET_DIR: MOV DL,0
- MOV AH,47H ;Get current directory.
- INT 21H
- RET
-
- CHANGE_DIR: MOV AH,3BH ;Change current directory.
- INT 21H
- RET
-
- CHANGE_DTA: MOV AH,1AH ;Set disk transfer address.
- INT 21H
- RET
-
- FIND_FIRST: MOV AH,4EH ;Find first matching file.
- INT 21H
- RET
-
- FIND_NEXT: MOV AH,4FH ;Find next matching file.
- INT 21H
- RET
-
- ;------------------------------------------------------;
- ; Two subroutines: One adds carriage return; linefeed. ;
- ; The other pads the file name display with spaces. ;
- ;------------------------------------------------------;
-
- CR_LF: MOV DL,13
- CALL DISPLAY
- MOV DL,10
- CALL DISPLAY
- RET
-
- SPACES: MOV DL,32
- CALL DISPLAY
- MOV DL,32
- CALL DISPLAY
- RET
-
- ;-----------------------------------------------------;
- ; This subroutine handles all the output. If /P was ;
- ; included, output will be echoed to the printer. ;
- ;-----------------------------------------------------;
-
- DISPLAY: CMP CS:PRINT_FLAG,1 ;If /P, echo to the printer.
- JNZ NOT_PRINTER
- MOV AH,5 ;Printer output.
- INT 21H
- NOT_PRINTER: MOV AH,2 ;Display output.
- INT 21H
- RET
-
- WRITE_IT: MOV DL,AL
- CALL DISPLAY
- WRITE_STRING: LODSB
- CMP AL,0 ;Zero marks end of string.
- JNZ WRITE_IT
- RET
-
- ;------------------------------------------------------------------;
- ; This subroutine will print the duplicate file name and its path. ;
- ;------------------------------------------------------------------;
-
- PRINT_MATCH: PUSH DS
- MOV CS:MATCH_FLAG,1 ;Flag that we have a duplicate.
- CMP CS:SOURCE_FLAG,1 ;Have we displayed source file?
- JZ SKIP_SOURCE ;If yes, skip.
- CALL CR_LF
- MOV CX,39 ;Separate duplicates with line.
- PRINT_LINE: MOV DL,'-'
- CALL DISPLAY
- LOOP PRINT_LINE
- MOV CS:SOURCE_FLAG,1 ;Flag displaying source.
- MOV AX,ES:[0] ;Retrieve directory number.
- CALL PRINT_DIR
- MOV SI,ES ;Point to file name
- CALL WRITE_FILE ;Display the file name and specs.
-
- SKIP_SOURCE: MOV AX,DS:[0] ;Retrieve directory number.
- CALL PRINT_DIR
- MOV SI,DS ;Point to file name.
- CALL WRITE_FILE
- POP DS
- RET
-
- ;----------------------------------------------;
- ; This subroutine displays the directory name. ;
- ;----------------------------------------------;
-
- PRINT_DIR: DEC AX ;Adjust as a pointer.
- MOV BL,65 ;Each directory record is 65.
- MUL BL
- MOV DI,AX
- PUSH DS
-
- PUSH CS ;Restore our data segment.
- POP DS
- MOV SI,OFFSET DIRECTORY ;Point to "Directory".
- CALL WRITE_STRING
- MOV SI,OFFSET DIRECTORIES ;Point to directory name.
- ADD SI,DI
- CALL WRITE_STRING
- CALL CR_LF ;Add carriage return linefeed.
-
- POP DS
- RET
-
- ;-------------------------------------------------------------------------;
- ; This subroutine handles displaying the file name, bytes, date and time. ;
- ;-------------------------------------------------------------------------;
-
- WRITE_FILE: PUSH DS
- MOV DS,SI ;Point to file name segment.
- MOV SI,10 ;Point to file name.
- CALL WRITE_STRING
-
- FILE_SIZE: MOV DX,DS:[8] ;Get high word of size
- MOV AX,DS:[6] ; and low word of size.
- MOV CX,10000 ;Divide by 10,000.
- DIV CX
- PUSH DX ;Save remainder.
- MOV BX,AX
- CALL NUMBERS ;Display ten thousands.
- POP BX ;Retrieve remainder.
- CALL THOUSANDS ;Display thousands.
-
- DATE: CALL SPACES ;Format to column 23.
- MOV SI,DS:[4] ;Retrieve date.
- MOV BX,SI ;Get month four bits.
- MOV CL,5
- ROR BX,CL
- AND BX,15
- MOV CS:DISPLAY_FLAG,0 ;And display.
- CALL TENS
-
- MOV DL,'-' ;Add hyphen.
- CALL DISPLAY
- MOV BX,SI
- AND BX,31 ;Retrieve day five bits.
- CALL TENS ;And display.
-
- MOV DL,'-' ;Add hyphen.
- CALL DISPLAY
- MOV BX,SI
- MOV CL,9 ;Retrieve year seven bits.
- ROR BX,CL
- AND BX,127
- ADD BX,80
- CALL TENS ;And display.
-
- TIME: CALL SPACES ;Format to column 33.
- MOV SI,DS:[2] ;Get time.
- MOV BX,SI
- MOV CL,11
- ROR BX,CL
- AND BX,31 ;Use hour five bits.
- PUSH BX
- CMP BX,12 ;Past noon?
- JBE MERIDIAN
- SUB BX,12 ;If yes, subtract 12.
- MERIDIAN: CMP BX,0 ;Is it midnight?
- JNZ NOT_MIDNIGHT
- MOV BX,12 ;If yes, display 12.
- NOT_MIDNIGHT: MOV CS:DISPLAY_FLAG,0
- CALL TENS ;And display.
- MOV DL,':' ;Add colon.
- CALL DISPLAY
- MOV BX,SI ;Retrieve minutes 6 bits.
- MOV CL,5
- ROR BX,CL
- AND BX,63
- CALL TENS ;And display.
- MOV DL,'p' ;Assume pm.
- POP BX
- CMP BX,12 ;Is it noon or later?
- JAE PM ;If yes, display "p".
- MOV DL,'a' ;Else, display "a".
- PM: CALL DISPLAY
- POP DS
- RET
-
- ;----------------------------------------------------------------------------;
- ; This subroutine displays each decimal position, suppressing leading zeros. ;
- ;----------------------------------------------------------------------------;
-
- NUMBERS: MOV CS:DISPLAY_FLAG,0 ;Reset the display flag.
- MOV CX,10000 ;Get ten thousands by dividing.
- CALL DIVIDE
- THOUSANDS: MOV CX,1000 ;Get thousands by dividing.
- CALL DIVIDE
- MOV CX,100 ;Get hundreds by dividing.
- CALL DIVIDE
- TENS: MOV CX,10 ;Get tens by dividing.
- CALL DIVIDE
- MOV CX,1 ;Get ones by dividing.
- CALL DIVIDE
- RET
-
- DIVIDE: MOV AX,BX ;Number in AX
- XOR DX,DX ; and zero in DX
- DIV CX ; divide by CX
- MOV BX,DX ; remainder into BX
- MOV DL,AL ; and quotient into DL.
- OR CS:DISPLAY_FLAG,AL ;If non zero indicate by flag.
- FLAG: CMP CS:DISPLAY_FLAG,0 ;Has there been a display?
- JNZ DISP_NUMBER ;If yes, display.
- MOV DL,-10H ;Else, display space.
- DISP_NUMBER: ADD DL,30H ;Convert hexadecimal to decimal
- CALL DISPLAY ;And display.
- END_LINE: RET
-
- STACK_SPACE:
- DTA EQU STACK_SPACE+200H
- SUBSCRIPTS EQU DTA+65
- CURRENT_DIR EQU SUBSCRIPTS+100
- STORAGE EQU CURRENT_DIR+65
- DIRECTORIES EQU STORAGE+44
-
- CODE ENDS
- END START
-